package com.uqbar.pacman.components;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import javax.imageio.ImageIO;

import ai.pathfinder.Node;
import ai.pathfinder.Pathfinder;

import com.uqbar.pacman.scenes.PacmanScene;
import com.uqbar.vainilla.DeltaState;
import com.uqbar.vainilla.GameComponent;
import com.uqbar.vainilla.appearances.Circle;
import com.uqbar.vainilla.exceptions.GameException;

public class Ghost extends GameComponent<PacmanScene> {
	private Pacman pacmanKnowlege;
	private double timeToStepfoward = 0;
	private double timeToScan = 0;
	private ArrayList<Node> path = new ArrayList<Node>();
	private ArrayList walkerMap= new ArrayList();
	private Pathfinder pf;
	private ArrayList<Position> walkables = new ArrayList<Position>();
	private int grupo = 2;
	
	
	
	public double getTimeToScan() {
		return timeToScan;
	}

	public void setTimeToScan(double timeToScan) {
		this.timeToScan = timeToScan;
	}

	public int getGrupo() {
		return grupo;
	}

	public void setGrupo(int grupo) {
		this.grupo = grupo;
	}

	public ArrayList<Position> getWalkables() {
		return walkables;
	}

	public void setWalkables(ArrayList<Position> walkables) {
		this.walkables = walkables;
	}

	public Ghost(Pacman pacman, double x, double y) {
			this.setAppearance(new Circle(new Color(0,0,0,0),30));
			this.setX(x);
			this.setY(y);
			this.pacmanKnowlege = pacman;
			this.walkerMap = this.GenerateMap();
			this.pf = new Pathfinder(walkerMap);
	}
	
	public void update(DeltaState deltaState){
		
		this.coordinarSkin();
			
		if(path.size() == 0 ||timeToScan<=0){
			Node ng = obtenerPosicion(this);
			Node np = obtenerPosicionPacman(this.pacmanKnowlege);
			if(ng!=null && np != null){
				path=pf.aStar(ng,np);
			}
			timeToScan= 0.3; 
		}
		
		if(timeToStepfoward <= 0){
			if(path.size()>=1){
				if(this.getX() == this.path.get(path.size()-1).x&&this.getY() == this.path.get(path.size()-1).y){
					this.setX(path.get(path.size()-1).x);
					this.setY(path.get(path.size()-1).y);				
					this.path.remove(path.size()-1);
				}else{
					this.adjustposition(this.path.get(path.size()-1));
				}
			}else{
				if(path.size()>0){
					this.path.remove(0);
				}
			}
			timeToStepfoward = 0.009;
		}else{
			timeToStepfoward = timeToStepfoward - deltaState.getDelta();
		}
		timeToScan= timeToScan - deltaState.getDelta();
	}
	
	public void coordinarSkin(){
		this.getScene().getBlinkySkin().setX(this.getX());
		this.getScene().getBlinkySkin().setY(this.getY());
	}

	private void adjustposition(Node node) {
		if(node.walkable){
			if(this.getX() < node.x){
				this.setX(this.getX()+1);
			}
		
			if(this.getY() < node.y){
				this.setY(this.getY()+1);
			}
		
			if(this.getX() > node.x){
				this.setX(this.getX()-1);
			}
		
			if(this.getY() > node.y){
				this.setY(this.getY()-1);
			}
		}
		
	}

	protected Node obtenerPosicion(GameComponent gc){
		boolean found = false;
		Node ret = null;
		for(int i = 0; i<this.walkerMap.size()&&!found;i++){
			Node n = (Node) walkerMap.get(i);
			if(!found && n.x == gc.getX()&& n.y == gc.getY()){
					ret = n;
					found = true;
			}
		}
		return ret;
	}
	
	protected Node obtenerPosicionPacman(GameComponent gc){
		boolean found = false;
		Node ret = null;
		for(int i = 0; i<this.walkerMap.size()&&!found;i++){
			Node n = (Node) walkerMap.get(i);
			if(!found && n.x > gc.getX()-15 && gc.getX()-15< n.x+30 && n.y > gc.getY()-15 && gc.getY()-15 < n.y+30){
					ret = n;
					found = true;
			}
		}
		return ret;
	}
	
	public boolean isBlack(int pixel) {
		  int red = (pixel >> 16) & 0xff;
		  int green = (pixel >> 8) & 0xff;
		  int blue = (pixel) & 0xff;
		  return red <= 75  && green <= 75 && blue <= 75;
	}
	
	
	private ArrayList GenerateMap(){
		ArrayList ret= this.walkerMap; 
		if(this.walkerMap.size() <= 0){
			ret = ProcessImageForPath("/map1rail.png");
		}
		return ret;
	}
	
	public ArrayList<Node> ProcessImageForPath(String imagePath){
		ArrayList<Node> ret = new ArrayList<Node>();
		
		BufferedImage img;
		try {
			img = ImageIO.read(Ghost.class.getResource(imagePath));
		}
		catch(Exception e) {
			throw new GameException("The resource '" + imagePath + "' was not found");
		}	
		int dimesionTiled= 30;
		//ix= indice X, iy=Indice y, Son el punto principal del "tile" ( 0 )
		//isx=Indice Sub X, isy= Indice Sub Y, son el area a escanear dentro del punto principal. ( 1 )
		//0----
		//| 1 |
		//-----
		Node prevN = null;
		for(int iy = 0; iy<img.getHeight();iy+=dimesionTiled){
			for(int ix=0; ix<img.getWidth();ix+=dimesionTiled){
				boolean found = false;
					for(int isy=iy; isy<iy+dimesionTiled;isy++){
						for(int isx=ix; isx<ix+dimesionTiled&&!found; isx++){
								if(!found&&isBlack(img.getRGB(isx, isy))){
									Node n = new Node(ix,iy);
									n.walkable = true;
									this.getWalkables().add(new Position(ix+10,iy+12));
									ret.add(n);									
									//conecta con la derecha
									if(n!=null&&prevN.walkable){
										n.connectBoth(prevN,dimesionTiled);
									}									

									//conecta con el de "arriba"
									Node tmpn = obtenerNodoSuperior(n,ret,dimesionTiled);
									if(tmpn!= null && tmpn.walkable){
										n.connectBoth(tmpn,dimesionTiled);
									}							
									prevN=n;
									found=true;
								}
						}
					}
					if(!found){
						Node n = new Node(ix,iy);
						n.walkable = false;
						ret.add(n);
						prevN=n;
					}
			}
		}
		return ret;
	}
	
	private Node obtenerNodoSuperior(Node n, ArrayList<Node> listnodes, int dimension) {
		Node ret = null;
		boolean found = false;
		for(int i = 0; i<listnodes.size()&&!found; i++){
			if(listnodes.get(i).x == n.x && listnodes.get(i).y == n.y-dimension ){
				ret=listnodes.get(i);
				found = true;
			}
		}
		return ret;
	}


}
